#ifndef HASIO_BUFFER_HPP
#define HASIO_BUFFER_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include <cstddef>

namespace hasio {

class mutable_buffer {
public:
    mutable_buffer()
        : data_(nullptr)
        , size_(0)
    {
    }

    mutable_buffer(void* data, size_t size)
        : data_(data)
        , size_(size)
    {
    }

    void* data() const
    {
        return data_;
    }

    std::size_t size() const
    {
        return size_;
    }

    mutable_buffer& operator+=(std::size_t n)
    {
        std::size_t offset = n < size_ ? n : size_;
        data_ = static_cast<char*>(data_) + offset;
        size_ -= offset;
        return *this;
    }

private:
    void* data_;
    std::size_t size_;
};

class const_buffer
{
public:
    const_buffer()
        : data_(nullptr)
        , size_(0)
    {
    }

    const_buffer(void* data, size_t size)
        : data_(data)
        , size_(size)
    {
    }

    const_buffer(const mutable_buffer &other)
        : data_(other.data())
        , size_(other.size())
    {
    }

    const void* data() const
    {
        return data_;
    }

    std::size_t size() const
    {
        return size_;
    }

    const_buffer& operator+=(std::size_t n)
    {
        std::size_t offset = n < size_ ? n : size_;
        data_ = static_cast<char*>(data_) + offset;
        size_ -= offset;
        return *this;
    }



private:
    void* data_;
    std::size_t size_;
};

namespace detail {
    struct one_buffer {};
    struct multiple_buffers {};

    template <typename Iterator>
    inline std::size_t buffer_size(multiple_buffers, Iterator begin, Iterator end)
    {
        std::size_t result = 0;
        for (Iterator iter = begin; iter != end; ++iter)
        {
            result += const_buffer(*iter).size();
        }
        return result;
    }

}

}

#endif // HASIO_BUFFER_HPP 